﻿using Base.Api.Models;
using Base.Api.Repository;
using Base.Data.Entity;
using Common.AspNetCore;
using Common.Infrastructure;
using Common.RunModels.FCP;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Base.Api.Service
{
    public class BaseInitService : CommonService
    {
        private readonly BaseRepository baseRepository;

        public BaseInitService(IServiceProvider provider, BaseRepository baseRep) : base(provider)
        {
            this.baseRepository = baseRep;
        }

        public async Task InitOrgAsync(FCPInitParam param)
        {
            LibCheckNullUtils.CheckNull(param.SrcOrgId, "param.SrcOrgId");
            if (param.DestOrgId == param.SrcOrgId)
            {
                return;
            }

            t_organization org = null;
            if (!string.IsNullOrEmpty(param.DestOrgId))
            {
                org = await this.baseRepository.CommonRepository.GetEntityAsync<t_organization>(param.DestOrgId);
            }
            else
            {
                LibCheckNullUtils.CheckNull(param.DestOrgCode, "param.DestOrgCode");
                LibCheckNullUtils.CheckNull(param.DestOrgName, "param.DestOrgName");

                org = new t_organization() { code = param.DestOrgCode, name = param.DestOrgName };
                this.SetEntityId(org);
                param.DestOrgId = org.id;

                await this.baseRepository.CommitChangesByCommonAsync(() =>
                {
                    this.baseRepository.CommonRepository.AddEntity(org);
                });
            }

            await AddOrgUserAsync(org, param.ApiKey);
            var re = await this.CallService.PostGetAsync<FCPInitReponse>("FCP", "FCP/InitOrg", param);
            await AddOrgMenuAsync(param, re.Forms);
        }

        public async Task InitSysAsync(FCPInitParam param)
        {
            var org = new t_organization() { code = param.DestOrgCode, name = param.DestOrgName };
            this.SetEntityId(org);
            param.DestOrgId = org.id;

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntity(org);
            });
            await AddOrgUserAsync(org, param.ApiKey);
            var re = await this.CallService.PostGetAsync<FCPInitReponse>("FCP", "FCP/InitSys", param);

            var menu1 = new t_menu()
            {
                num = 1,
                label = "测试1",
                org_id = org.id,
            };
            this.SetEntityId(menu1);

            var menu2 = new t_menu()
            {
                num = 2,
                label = "测试2",
                org_id = org.id,
            };
            this.SetEntityId(menu2);

            var menu3 = new t_menu()
            {
                num = 1,
                label = "测试1-1",
                org_id = org.id,
                parent_id = menu1.id
            };
            this.SetEntityId(menu3);

            var menu4 = new t_menu()
            {
                num = 2,
                label = "测试1-2",
                org_id = org.id,
                parent_id = menu1.id
            };
            this.SetEntityId(menu4);

            var menu5 = new t_menu()
            {
                num = 1,
                label = "测试1-1-1",
                org_id = org.id,
                parent_id = menu3.id
            };
            this.SetEntityId(menu5);
            if (re.Forms != null && re.Forms.Count >= 12)
            {
                menu5.fcp_form_id = re.Forms[0].DestFormId;
            }

            var menu6 = new t_menu()
            {
                num = 2,
                label = "测试1-1-1",
                org_id = org.id,
                parent_id = menu3.id
            };
            if (re.Forms != null && re.Forms.Count >= 2)
            {
                menu6.fcp_form_id = re.Forms[1].DestFormId;
            }

            this.SetEntityId(menu6);

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntity(menu1);
                this.baseRepository.CommonRepository.AddEntity(menu2);
                this.baseRepository.CommonRepository.AddEntity(menu3);
                this.baseRepository.CommonRepository.AddEntity(menu4);
                this.baseRepository.CommonRepository.AddEntity(menu5);
                this.baseRepository.CommonRepository.AddEntity(menu6);
            });
        }

        public async Task<List<string>> GetInitSqlAsync(BaseInitSqlRequest request)
        {
            if (string.IsNullOrEmpty(request.DestOrgId))
            {
                request.DestOrgId = request.OrgId;
            }

            List<string> ret = new List<string>();
            var org = await this.baseRepository.CommonRepository.GetEntityAsync<t_organization>(request.OrgId);
            LibSysUtils.GetSqlByEntity(request.DbType, org, ret, request.DestOrgId, 1);
            await DoGetInitSqlAsync<t_user>(request, ret);
            await DoGetInitSqlAsync<t_member>(request, ret);
            await DoGetInitSqlAsync<t_role>(request, ret);
            await DoGetInitSqlAsync<t_member_auth_role>(request, ret);
            await DoGetInitSqlAsync<t_menu>(request, ret);
            return ret;
        }

        private async Task AddOrgUserAsync(t_organization org, string apiKey)
        {
            t_user user = new t_user() { org_id = org.id, code = org.code + "Admin", name = org.code + "Admin" };
            var userD = await this.baseRepository.CommonRepository.GetEntityAsync<t_member>(null, t => t.code == user.code);
            if (userD != null)
            {
                return;
            }

            this.SetEntityId(user);

            t_user sysuser = new t_user() { org_id = org.id, code = org.code + "System", name = org.code + "System", api_key = apiKey };
            this.SetEntityId(sysuser);
            t_member sysmember = new t_member() { org_id = org.id, code = org.code + "System", name = org.code + "System", user_id = sysuser.id, password = "e10adc3949ba59abbe56e057f20f883e", api_key = apiKey };
            this.SetEntityId(sysmember);
            t_member member = new t_member() { org_id = org.id, code = org.code + "Admin", name = org.code + "Admin", user_id = user.id, password = "e10adc3949ba59abbe56e057f20f883e", api_key = apiKey };

            var depart = new t_department()
            {
                org_id = org.id,
                code = org.code + "System",
                name = org.code + "System",
                api_key = apiKey
            };
            this.SetEntityId(depart);

            sysmember.depart_id = depart.id;
            member.depart_id = depart.id;
            sysuser.depart_id = depart.id;
            user.depart_id = depart.id;

            t_role role = new t_role() { org_id = org.id, role_type = 1, platform_type = 0, code = org.code + "Admin", name = org.code + "Admin" };
            t_role clientrole = new t_role() { org_id = org.id, role_type = 1, platform_type = 1, code = org.code + "ClientAdmin", name = org.code + "ClientAdmin" };
            t_role approle = new t_role() { org_id = org.id, role_type = 1, platform_type = 2, code = org.code + "AppAdmin", name = org.code + "AppAdmin" };
            t_role winformrole = new t_role() { org_id = org.id, role_type = 1, platform_type = 3, code = org.code + "WinformAdmin", name = org.code + "WinformAdmin" };

            this.SetEntityId(member);
            this.SetEntityId(role);
            this.SetEntityId(clientrole);
            this.SetEntityId(approle);
            this.SetEntityId(winformrole);

            var authRole = new t_member_auth_role() { member_id = member.id, role_id = role.id, org_id = member.org_id };
            var clientauthRole = new t_member_auth_role() { member_id = member.id, role_id = clientrole.id, org_id = member.org_id };
            var appauthRole = new t_member_auth_role() { member_id = member.id, role_id = approle.id, org_id = member.org_id };
            var winformauthRole = new t_member_auth_role() { member_id = member.id, role_id = winformrole.id, org_id = member.org_id };

            this.SetEntityId(authRole);
            this.SetEntityId(clientauthRole);
            this.SetEntityId(appauthRole);
            this.SetEntityId(winformauthRole);

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntity(user);
                this.baseRepository.CommonRepository.AddEntity(member);
                this.baseRepository.CommonRepository.AddEntity(role);
                this.baseRepository.CommonRepository.AddEntity(clientrole);
                this.baseRepository.CommonRepository.AddEntity(approle);
                this.baseRepository.CommonRepository.AddEntity(winformrole);
                this.baseRepository.CommonRepository.AddEntity(sysuser);
                this.baseRepository.CommonRepository.AddEntity(sysmember);
                this.baseRepository.CommonRepository.AddEntity(authRole);
                this.baseRepository.CommonRepository.AddEntity(clientauthRole);
                this.baseRepository.CommonRepository.AddEntity(appauthRole);
                this.baseRepository.CommonRepository.AddEntity(winformauthRole);
                this.baseRepository.CommonRepository.AddEntity(depart);
            });
        }

        private async Task AddOrgMenuAsync(FCPInitParam param, List<FCPInitFormReponse> forms)
        {
            List<t_menu> addMenus = new List<t_menu>();
            var menus2 = await this.baseRepository.CommonRepository.GetEntityAsync<t_menu>(null, t => t.org_id == param.DestOrgId);
            if (menus2 != null)
            {
                return;
            }

            var menus = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_menu>(t => t.org_id == param.SrcOrgId);

            DoAddOrgMenu(param, menus, null, null, forms, addMenus);

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntities(addMenus);
            });
        }

        private void DoAddOrgMenu(FCPInitParam param, List<t_menu> srcEntitis, string destParentId, string srcParentId, List<FCPInitFormReponse> forms, List<t_menu> addMenus)
        {
            var stt = srcEntitis.Where(t => t.parent_id == srcParentId);
            foreach (var t in stt)
            {
                var mm = new t_menu();
                LibSysUtils.CopyObject(mm, t);
                this.SetEntityId(mm);
                mm.org_id = param.DestOrgId;
                mm.parent_id = destParentId;
                var fo = t.fcp_form_id != null ? forms.FirstOrDefault(t1 => t1.SrcFormId == t.fcp_form_id) : null;
                mm.fcp_form_id = fo?.DestFormId;
                addMenus.Add(mm);
                DoAddOrgMenu(param, srcEntitis, mm.id, t.id, forms, addMenus);
            }
        }

        private async Task DoGetInitSqlAsync<T>(BaseInitSqlRequest request, List<string> sqls)
            where T : EntityBase, new()
        {
            var ts = await this.baseRepository.CommonRepository.GetEntitiesAsync<T>(t => t.org_id == request.OrgId);
            ts.ForEach(t =>
            {
                LibSysUtils.GetSqlByEntity(request.DbType, t, sqls, request.DestOrgId, 1);
            });
        }
    }
}
